package com.xique.park.service.service.impl;


import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xique.common.core.domain.R;
import com.xique.common.core.enums.PayStatus;
import com.xique.common.core.enums.PayType;
import com.xique.common.core.enums.TransTypeEnum;
import com.xique.common.core.utils.AliossUtil;
import com.xique.common.core.utils.SecurityUtils;
import com.xique.common.core.utils.poi.ExcelUtil;
import com.xique.common.core.web.domain.AjaxResult;
import com.xique.common.core.web.domain.PageResult;
import com.xique.park.bean.dto.ExcelPayBeanDto;
import com.xique.park.bean.dto.ParkInDto;
import com.xique.park.bean.dto.ParkOutDto;
import com.xique.park.bean.dto.PayOrderExportIcbcDto;
import com.xique.park.bean.request.client.OpenGateRequest;
import com.xique.park.bean.request.comm.ParkOnListRequest;
import com.xique.park.bean.request.web.onDuty.OnDutySettlementRequest;
import com.xique.park.bean.request.web.parkingOrder.ParkingOrderRequest;
import com.xique.park.bean.request.web.payorder.PayOrderRequest;
import com.xique.park.bean.vo.client.OpenGateVo;
import com.xique.park.bean.vo.comm.ParkOnVo;
import com.xique.park.bean.vo.web.onDuty.OnDutySettlementVo;
import com.xique.park.bean.vo.web.parkingOrder.ParkingOrderVo;
import com.xique.park.bean.vo.web.payOrder.ExcelExportIncomeBean;
import com.xique.park.bean.vo.web.payOrder.PayOrderVo;
import com.xique.park.bean.vo.web.statistics.ParkStatisticsIncomeVo;
import com.xique.park.constant.ExcelConstant;
import com.xique.park.enums.PayChannelEnum;
import com.xique.park.mapper.ParkStatisticsIncomeMapper;
import com.xique.park.mapper.ParkingOrderMapper;
import com.xique.park.mapper.PayOrderMapper;
import com.xique.park.service.biz.service.IParkOnBizService;
import com.xique.park.service.service.*;
import com.xique.park.utils.ExportExcelUtils;
import com.xique.park.utils.TotalRowHandler;
import com.xique.system.api.RemoteSystemProjectService;
import com.xique.system.api.RemoteSystemUserService;
import com.xique.system.api.dto.OperateDTO;
import com.xique.system.api.dto.SystemProjectDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class ExportServiceImpl implements ExportService {

    private final ParkStatisticsIncomeMapper parkStatisticsIncomeMapper;

    private final IParkInService parkInService;

    private final IParkOutService parkOutService;

    private final PayOrderMapper payOrderMapper;

    private final AliossUtil aliossUtil;

    private final IParkClientService parkClientService;

    private final RemoteSystemUserService remoteSystemUserService;

    private final RemoteSystemProjectService remoteSystemProjectService;

    private final IParkOnBizService iParkOnBizService;

    private final IParkingOrderService iParkingOrderService;

    private final ParkingOrderMapper parkingOrderMapper;

    private static final String TIME_ZERO = "00:00:00";

    /**
     * 导出-收入记录
     */
    @Override
    public void exportIncomeStatistics(HttpServletResponse response, long parkId, Integer type, String startTime, String endTime) throws IOException {

        OutputStream out = response.getOutputStream();
        response.setHeader("Content-disposition",
                "attachment; filename=" + "income-" + ".xlsx");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf8");
        ExcelWriter excelWriter = EasyExcel.write(out).build();
        List<ParkStatisticsIncomeVo> parkStatisticsIncomeVos;
        String s ;
        switch (type) {
            // 按日
            case 1:
               parkStatisticsIncomeVos = parkStatisticsIncomeMapper.selectPageByDay(parkId, startTime, endTime);
               s ="日";
                handlePageResult(parkStatisticsIncomeVos);
               break;
            // 按月
            case 2:
                parkStatisticsIncomeVos = parkStatisticsIncomeMapper.selectPageByMonth(parkId, startTime, endTime);
                s ="月";
                handlePageResult(parkStatisticsIncomeVos);
                break;
            // 按年
            case 3:
                parkStatisticsIncomeVos = parkStatisticsIncomeMapper.selectPageByYear(parkId, startTime, endTime);
                s ="年";
                handlePageResult(parkStatisticsIncomeVos);
                break;
            default:
                throw new IllegalArgumentException("收入统计报表查询类型错误，请联系管理员");
        };

        List<List<String>> dataList = getData(parkStatisticsIncomeVos);
        List<List<String>> headList = getHeadList();
        TotalRowHandler totalRowHandler = new TotalRowHandler(dataList.size());
        HashSet<String> totalHeadSet = getTotalHeadSet();
        try{
          WriteSheet writeSheet = EasyExcel.writerSheet(0, s+"收入记录").head(ExcelExportIncomeBean.class)
                  .registerWriteHandler(totalRowHandler).build();
          ExportExcelUtils.addTotalRow(headList,dataList,totalHeadSet);
          excelWriter.write(dataList, writeSheet);
          excelWriter.finish();
      }finally {
          if (out != null) {
              try {
                  out.close();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
    }

    /**
     * 处理数据格式
     * @return
     */
    private List<List<String>> getData(List<ParkStatisticsIncomeVo> parkStatisticsIncomeVos){
        List<ExcelExportIncomeBean> excelExportIncomeBeans =new ArrayList<>();
        List<List<String>> dataList = new ArrayList<>();
        parkStatisticsIncomeVos.forEach(a->{
            List<String> data = new ArrayList<>();
            ExcelExportIncomeBean excelExportIncomeBean = new ExcelExportIncomeBean();
            BeanUtils.copyProperties(a,excelExportIncomeBean);
            data.add(excelExportIncomeBean.getStatisticalTimeStr());
            data.add(excelExportIncomeBean.getTotal().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
            data.add(excelExportIncomeBean.getMonthlyCardCash().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
            data.add(excelExportIncomeBean.getMonthlyCardElectronics().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
            data.add(excelExportIncomeBean.getMonthlyTotal().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
            data.add(excelExportIncomeBean.getTemporaryCash().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
            data.add(excelExportIncomeBean.getTemporaryElectronics().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
            data.add(excelExportIncomeBean.getTemporaryEtc().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
            data.add(excelExportIncomeBean.getTemporaryTotal().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
            data.add(excelExportIncomeBean.getStoredValueCash().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
            data.add(excelExportIncomeBean.getStoredValueElectronics().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
            data.add(excelExportIncomeBean.getStoredValueTotal().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
            data.add(excelExportIncomeBean.getBusinessCash().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
            data.add(excelExportIncomeBean.getBusinessTotal().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString());
            dataList.add(data);
            excelExportIncomeBeans.add(excelExportIncomeBean);
        });
        return dataList;
    };

    /**
     * 处理表头
     * @param
     */
      private   List<List<String>> getHeadList(){
        List<List<String>> headList = new ArrayList<>();
        List<String> head = new ArrayList<>();head.add("统计时间");headList.add(head);
        List<String> head1 = new ArrayList<>();head1.add("总计");headList.add(head1);
        List<String> head2 = new ArrayList<>();head2.add("月卡现金收入");headList.add(head2);
        List<String> head3 = new ArrayList<>();head3.add("月卡电子支付");headList.add(head3);
        List<String> head4 = new ArrayList<>();head4.add("月卡合计");headList.add(head4);
        List<String> head5 = new ArrayList<>();head5.add("临停现金收入");headList.add(head5);
        List<String> head6 = new ArrayList<>();head6.add("临停电子支付");headList.add(head6);
        List<String> head7 = new ArrayList<>();head7.add("临停etc收入");headList.add(head7);
        List<String> head8 = new ArrayList<>();head8.add("临停合计");headList.add(head8);
        List<String> head9 = new ArrayList<>();head9.add("储值现金收入");headList.add(head9);
        List<String> head10 = new ArrayList<>();head10.add("储值电子收入");headList.add(head10);
        List<String> head11 = new ArrayList<>();head11.add("储值合计");headList.add(head11);
        List<String> head12 = new ArrayList<>();head12.add("商家现金收入");headList.add(head12);
        List<String> head13 = new ArrayList<>();head13.add("商家合计");headList.add(head13);
        return headList;
    }

    /**
     * 处理合计列
     * @param
     */
     private HashSet<String> getTotalHeadSet(){
         HashSet<String> totalHeadSet = new HashSet<>();
         totalHeadSet.add("总计");
         totalHeadSet.add("月卡现金收入");totalHeadSet.add("月卡电子支付");totalHeadSet.add("月卡合计");
         totalHeadSet.add("临停现金收入");totalHeadSet.add("临停电子支付"); totalHeadSet.add("临停etc收入"); totalHeadSet.add("临停合计");
         totalHeadSet.add("储值现金收入");totalHeadSet.add("储值电子收入"); totalHeadSet.add("储值合计");
          totalHeadSet.add("商家现金收入");  totalHeadSet.add("商家合计");
         return totalHeadSet;
     }





    private void handlePageResult(List<ParkStatisticsIncomeVo> parkStatisticsIncomeVoList) {
        if (CollUtil.isNotEmpty(parkStatisticsIncomeVoList)) {
            parkStatisticsIncomeVoList.forEach(parkStatisticsIncomeVo -> {
                // 月卡现金收入
                BigDecimal monthlyCardCash = parkStatisticsIncomeVo.getMonthlyCardCash();

                // 月卡电子支付
                BigDecimal monthlyCardElectronics = parkStatisticsIncomeVo.getMonthlyCardElectronics();

                // 月卡收入合计
                BigDecimal monthlyTotal = monthlyCardCash.add(monthlyCardElectronics);
                parkStatisticsIncomeVo.setMonthlyTotal(monthlyTotal);

                // 临停现金收入
                BigDecimal temporaryCash = parkStatisticsIncomeVo.getTemporaryCash();

                // 临停电子支付
                BigDecimal temporaryElectronics = parkStatisticsIncomeVo.getTemporaryElectronics();

                // 临停etc收入
                BigDecimal temporaryEtc = parkStatisticsIncomeVo.getTemporaryEtc();

                // 临停收入合计
                BigDecimal temporaryTotal = temporaryCash.add(temporaryElectronics).add(temporaryEtc);
                parkStatisticsIncomeVo.setTemporaryTotal(temporaryTotal);

                // 储值现金收入
                BigDecimal storedValueCash = parkStatisticsIncomeVo.getStoredValueCash();

                // 储值电子收入
                BigDecimal storedValueElectronics = parkStatisticsIncomeVo.getStoredValueElectronics();

                // 储值收入合计
                BigDecimal storedValueTotal = storedValueCash.add(storedValueElectronics);
                parkStatisticsIncomeVo.setStoredValueTotal(storedValueTotal);

                // 商家现金收入，商家收入合计
                parkStatisticsIncomeVo.setBusinessTotal(parkStatisticsIncomeVo.getBusinessCash());

                // 总收入
                BigDecimal total = monthlyTotal.add(temporaryTotal).add(storedValueTotal).add(parkStatisticsIncomeVo.getBusinessCash());
                parkStatisticsIncomeVo.setTotal(total);

                // 统计时间处理
                String statisticalTimeStr = parkStatisticsIncomeVo.getStatisticalTimeStr();
                if (StrUtil.isNotBlank(statisticalTimeStr) && statisticalTimeStr.contains(TIME_ZERO)) {
                    statisticalTimeStr = statisticalTimeStr.substring(0, statisticalTimeStr.lastIndexOf(TIME_ZERO));
                    parkStatisticsIncomeVo.setStatisticalTimeStr(statisticalTimeStr);
                }
            });
        }
    }

    @Override
    public void exportPayRecord(HttpServletResponse response, PayOrderRequest payOrderRequest) throws IOException {
        // 根据项目配置的支付渠道，导出不同的excel
        Long parkId = payOrderRequest.getParkId();
        R<SystemProjectDTO> systemProjectR = remoteSystemProjectService.getProjectInfo(parkId);
        if (null != systemProjectR && null != systemProjectR.getData()) {
            SystemProjectDTO systemProject = systemProjectR.getData();
            String payChannel = systemProject.getPayChannel();
            if (StrUtil.equals(payChannel, PayChannelEnum.PP.getChannel())) {
                // PP
                payOrderRequest.setPayChannel(PayChannelEnum.PP.getChannel());
                exportPayRecordToPp(response, payOrderRequest);
            } else if (StrUtil.equals(payChannel, PayChannelEnum.ICBC.getChannel())) {
                // ICBC
                payOrderRequest.setPayChannel(PayChannelEnum.ICBC.getChannel());
                exportPayRecordToIcbc(response, payOrderRequest);
            } else {
                log.warn("[导出服务]-支付记录导出，支付渠道未匹配,{},{}", parkId, systemProject);
                throw new IllegalArgumentException("车场支付渠道未匹配");
            }
        } else {
            log.warn("[导出服务]-支付记录导出，车场信息获取失败,{}", parkId);
            throw new IllegalArgumentException("车场信息获取失败");
        }
    }

    private void exportPayRecordToIcbc(HttpServletResponse response, PayOrderRequest payOrderRequest) {
        ExcelWriter excelWriter = null;
        try {
            String fileName = URLEncoder.encode("支付记录.xlsx", "UTF-8");

            response.setCharacterEncoding("UTF-8");
            response.setHeader("Content-disposition", "attachment; filename=" + fileName);
            response.setContentType("application/x-xls");

            OutputStream out = response.getOutputStream();
            excelWriter = EasyExcelFactory.write(out, PayOrderExportIcbcDto.class).build();

            String transType = payOrderRequest.getTransType();
            if (StrUtil.isBlank(transType)) {
                // 如果未指定交易类型，则导出全部交易类型
                // 导出月卡续费
                payOrderRequest.setTransType(TransTypeEnum.MONTHLY_CARD.getType());
                exportPayRecordToIcbcByTransType(payOrderRequest, excelWriter);
                // 导出余额充值
                payOrderRequest.setTransType(TransTypeEnum.RECHARGE.getType());
                exportPayRecordToIcbcByTransType(payOrderRequest, excelWriter);
                // 导出临时缴费
                payOrderRequest.setTransType(TransTypeEnum.TEMPORARY.getType());
                exportPayRecordToIcbcByTransType(payOrderRequest, excelWriter);
            } else {
                // 如果指定了交易类型，则只导出此交易类型
                exportPayRecordToIcbcByTransType(payOrderRequest, excelWriter);
            }
        } catch (UnsupportedEncodingException e) {
            log.error("[导出服务]-工行支付记录导出，编码格式错误");
            e.printStackTrace();
        } catch (IOException e) {
            log.error("[导出服务]-工行支付记录导出，IO异常");
            e.printStackTrace();
        } finally {
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }

    private void exportPayRecordToIcbcByTransType(PayOrderRequest payOrderRequest, ExcelWriter excelWriter) {
        String sheetName;
        String transType = payOrderRequest.getTransType();
        if (StrUtil.equals(transType, TransTypeEnum.MONTHLY_CARD.getType())) {
            sheetName = TransTypeEnum.MONTHLY_CARD.getName();
        } else if (StrUtil.equals(transType, TransTypeEnum.RECHARGE.getType())) {
            sheetName = TransTypeEnum.RECHARGE.getName();
        } else if (StrUtil.equals(transType, TransTypeEnum.TEMPORARY.getType())) {
            sheetName = TransTypeEnum.TEMPORARY.getName();
        } else {
            sheetName = "支付记录";
        }

        long totalSize = selectIcbcPayOrderCount(payOrderRequest);
        if (totalSize > 0) {
            long totalPages = totalSize / ExcelConstant.PER_WRITE_ROW_COUNT + 1;
            log.info("[导出服务]-工行支付记录导出，sheetName:{},请求参数：{}，总条数：{}，总页数：{}，每页数量：{}", sheetName, payOrderRequest, totalSize, totalPages, ExcelConstant.PER_WRITE_ROW_COUNT);

            for (int pageNum = 1; pageNum <= totalPages; pageNum++) {
                long startTime = System.currentTimeMillis();

                log.info("[导出服务]-工行支付记录导出,开始到导出第{}页", pageNum);

                // 分页查询结算记录
                payOrderRequest.setPageNum(pageNum);
                payOrderRequest.setPageSize(ExcelConstant.PER_WRITE_ROW_COUNT);
                IPage<PayOrderExportIcbcDto> payOrderExportIcbcDtoPage = selectIcbcPayOrderExportPage(payOrderRequest);
                List<PayOrderExportIcbcDto> parkSettlementRecordList = payOrderExportIcbcDtoPage.getRecords();

                // 导出
                WriteSheet writeSheet = EasyExcelFactory.writerSheet(pageNum, sheetName + pageNum).build();
                excelWriter.write(parkSettlementRecordList, writeSheet);

                log.info("[导出服务]-工行支付记录导出,第{}页到导出完成，耗时：{}", pageNum, System.currentTimeMillis() - startTime);
            }
        }
    }

    private IPage<PayOrderExportIcbcDto> selectIcbcPayOrderExportPage(PayOrderRequest payOrderRequest) {
        Page<PayOrderExportIcbcDto> page = new Page<>();
        page.setCurrent(payOrderRequest.getPageNum());
        page.setSize(payOrderRequest.getPageSize());
        return payOrderMapper.selectPayOrderExportPage(page, payOrderRequest);
    }

    private long selectIcbcPayOrderCount(PayOrderRequest payOrderRequest) {
        return payOrderMapper.selectIcbcPayOrderCount(payOrderRequest);
    }

    private void exportPayRecordToPp(HttpServletResponse response, PayOrderRequest payOrderRequest) throws IOException {
        if (2 == payOrderRequest.getExportType()) {
            payOrderRequest.setPayType(Collections.singletonList(PayType.WX_PAY.getType()));
        } else if (3 == payOrderRequest.getExportType()) {
            payOrderRequest.setPayType(Collections.singletonList(PayType.ALI_PAY.getType()));
        } else if (4 == payOrderRequest.getExportType()) {
            payOrderRequest.setPayType(Collections.singletonList(PayType.ETC.getType()));
        } else if (5 == payOrderRequest.getExportType()) {
            payOrderRequest.setPayType(Collections.singletonList(PayType.SAVINGS.getType()));
        } else if (6 == payOrderRequest.getExportType()) {
            payOrderRequest.setPayType(Collections.singletonList(PayType.CASH.getType()));
        } else if (7 == payOrderRequest.getExportType()) {
            payOrderRequest.setPayType(Arrays.asList(PayType.P_CLOUD.getType(), PayType.OTHER.getType()));
        }

        long startTime = System.currentTimeMillis();
        OutputStream out = response.getOutputStream();
        //添加响应头信息
        response.setHeader("Content-disposition",
                "attachment; filename=" + "payRecord-" + payOrderRequest.getPayStartTime() + "-" + payOrderRequest.getPayEndTime() + ".xlsx");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf8");
        ExcelWriter excelWriter = EasyExcelFactory.write(out).build();
        try {
            Integer totalRowCount = payOrderMapper.selectPayOderCount(payOrderRequest);
            Integer pageSize = ExcelConstant.PER_WRITE_ROW_COUNT;
            int writeCount = totalRowCount % pageSize == 0 ? (totalRowCount / pageSize) : (totalRowCount / pageSize + 1);
            for (int i = 0; i < writeCount; i++) {
                ArrayList<ExcelPayBeanDto> payBeanDtos = new ArrayList<>();
                Page<PayOrderVo> page = new Page<>();
                page.setCurrent(i + 1);
                page.setSize(pageSize);
                IPage<PayOrderVo> payOrderVoPage = payOrderMapper.selectPageList(page, payOrderRequest);
                List<PayOrderVo> records = payOrderVoPage.getRecords();

                if (CollUtil.isNotEmpty(records)) {
                    StringBuilder operateIds = new StringBuilder();
                    records.forEach(payOrderVo -> {
                        Long updateUserId = payOrderVo.getUpdateUser();
                        if (null != updateUserId) {
                            operateIds.append(updateUserId).append(",");
                        }
                    });
                    // 赋值操作人信息
                    if (StrUtil.isNotBlank(operateIds)) {
                        R<List<OperateDTO>> updateUserResult = remoteSystemUserService.getOperateList(operateIds.toString());
                        if (null != updateUserResult.getData()) {
                            List<OperateDTO> operateDTOList = updateUserResult.getData();
                            if (CollUtil.isNotEmpty(operateDTOList)) {
                                Map<Long, String> operateMap = operateDTOList.stream().collect(Collectors.toMap(OperateDTO::getOperateId, OperateDTO::getOperateName));
                                records.forEach(payOrderVo -> payOrderVo.setUpdateBy(operateMap.get(payOrderVo.getUpdateUser())));
                            }
                        }
                    }
                }
                 if (CollectionUtils.isNotEmpty(records)){
                     records.forEach(payOrderVo -> {
                         ExcelPayBeanDto excelPayBeanDto = new ExcelPayBeanDto();
                         BeanUtils.copyProperties(payOrderVo,excelPayBeanDto);
                         excelPayBeanDto.setActualFee(payOrderVo.getAmt().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));

                        payBeanDtos.add(excelPayBeanDto);
                    });
                    WriteSheet writeSheet = EasyExcelFactory.writerSheet(0, "支付记录").head(ExcelPayBeanDto.class)
                            .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
                    excelWriter.write(payBeanDtos, writeSheet);
                    excelWriter.finish();
                }
            }
            excelWriter.finish();
            out.flush();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        long endTime = System.currentTimeMillis();
        log.info("导出花费时间为{}毫秒", endTime - startTime);
    }

    @Override
    public void exportFeeList(OnDutySettlementRequest request, HttpServletResponse response) throws IOException {
        ExcelUtil<OnDutySettlementVo> util = new ExcelUtil<>(OnDutySettlementVo.class);
        Long clientUserId = request.getClientUserId();
        String plate = request.getPlate();
        String payType = PayType.FREE.getType();
        String beginTime = request.getStartTime();
        String endTime = request.getEndTime();
        List<PayOrderVo> payOrderVos = payOrderMapper.selectPageListByPayType(clientUserId, plate, payType, beginTime, endTime);


        List<OnDutySettlementVo> onDutySettlementVos = handleResult(payOrderVos);

        util.exportExcel(response, onDutySettlementVos, "免费放行记录");
    }

    /**
     * 手动开闸导出记录
     */
    @Override
    public void exportOpenGate(OpenGateRequest request, HttpServletResponse response) throws IOException {
        ExcelUtil<OpenGateVo> util = new ExcelUtil<>(OpenGateVo.class);
        request.setParkId(SecurityUtils.getParkId());

        List<OpenGateVo> openGateVos = parkClientService.selectOpenGateRecords(request);

        util.exportExcel(response, openGateVos, "手动开闸记录");
    }

    @Override
    public void exportParkOnList(HttpServletResponse response, ParkOnListRequest request) throws IOException {
        ExcelUtil<ParkOnVo> util = new ExcelUtil<>(ParkOnVo.class);
        request.setPageSize(-1);
        AjaxResult parkOnLst = iParkOnBizService.getParkOnLst(request);
        Map<String, List<ParkOnVo>> map = (Map<String, List<ParkOnVo>>) parkOnLst.get("data");
        List<ParkOnVo> list = map.get("list");
        util.exportExcel(response, list, "在场车辆数据");
    }

    @Override
    public void exportParkOrderList(ParkingOrderRequest parkingOrderRequest, HttpServletResponse response) throws IOException {
        if (2 == parkingOrderRequest.getExportType()) {
            parkingOrderRequest.setPayStatus(Arrays.asList(PayStatus.PAID.getStatus(), PayStatus.CASH_PAID.getStatus()));
        } else if (3 == parkingOrderRequest.getExportType()) {
            parkingOrderRequest.setPayStatus(Collections.singletonList(PayStatus.FREE.getStatus()));
        } else if (4 == parkingOrderRequest.getExportType()) {
            parkingOrderRequest.setPayStatus(Collections.singletonList(PayStatus.WAIT_PAID.getStatus()));
        } else if (5 == parkingOrderRequest.getExportType()) {
            parkingOrderRequest.setPayStatus(Collections.singletonList(PayStatus.CANCEL.getStatus()));
        } else if (6 == parkingOrderRequest.getExportType()) {
            parkingOrderRequest.setPayStatus(Collections.singletonList(PayStatus.WAIT_PAID.getStatus()));
        }

        long startTime = System.currentTimeMillis();
        OutputStream out = response.getOutputStream();
        //添加响应头信息
        response.setHeader("Content-disposition",
                "attachment; filename=" + "payRecord-" + parkingOrderRequest.getStartTime() + "-" + parkingOrderRequest.getEndTime() + ".xlsx");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf8");
        ExcelWriter excelWriter = EasyExcelFactory.write(out).build();
        try {
            Integer totalRowCount = parkingOrderMapper.selectParkOrderCount(parkingOrderRequest);
            Integer pageSize = ExcelConstant.PER_WRITE_ROW_COUNT;
            int writeCount = totalRowCount % pageSize == 0 ? (totalRowCount / pageSize) : (totalRowCount / pageSize + 1);
            for (int i = 0; i < writeCount; i++) {
                parkingOrderRequest.setPageNum(i + 1);
                parkingOrderRequest.setPageSize(pageSize);
                PageResult pageResult = iParkingOrderService.selectPageList(parkingOrderRequest);
                List<ParkingOrderVo> records = (List<ParkingOrderVo>) pageResult.getList();
                if (CollectionUtils.isNotEmpty(records)) {
                    WriteSheet writeSheet = EasyExcelFactory.writerSheet(0, "停车订单记录").head(ParkingOrderVo.class)
                            .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
                    excelWriter.write(records, writeSheet);
                    excelWriter.finish();
                }
            }
            excelWriter.finish();
            out.flush();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        long endTime = System.currentTimeMillis();
        log.info("导出花费时间为{}毫秒", endTime - startTime);
    }

    /**
     * 导出现金收费记录
     */
    @Override
    public void exportNoChargeList(OnDutySettlementRequest request, HttpServletResponse response) throws IOException {
        ExcelUtil<OnDutySettlementVo> util = new ExcelUtil<>(OnDutySettlementVo.class);
        Long clientUserId = request.getClientUserId();
        String plate = request.getPlate();
        String beginTime = request.getStartTime();
        String endTime = request.getEndTime();

        // 查询未收费金额和支付信息
        List<PayOrderVo> payOrderVos = payOrderMapper.selectPageNoChargeList(clientUserId, plate, beginTime, endTime);

        // 处理查询结果
        List<OnDutySettlementVo> onDutySettlementVoList = handleResult(payOrderVos);
        util.exportExcel(response, onDutySettlementVoList, "现金收费记录");
    }

    /**
     * 处理分页查询结果
     */
    private List<OnDutySettlementVo> handleResult(List<PayOrderVo> payOrderVoList) {
        List<OnDutySettlementVo> onDutySettlementVoList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(payOrderVoList)) {
            payOrderVoList.forEach(payOrderVo -> {
                OnDutySettlementVo onDutySettlementVo = new OnDutySettlementVo();
                onDutySettlementVo.setPlate(payOrderVo.getPlate());
                onDutySettlementVo.setAmt(payOrderVo.getAmt().divide(new BigDecimal(100), 2, RoundingMode.HALF_UP));
                onDutySettlementVo.setRemark(payOrderVo.getRemark());
                if (null == payOrderVo.getSettlementStatus()) {
                    onDutySettlementVo.setSettlementStatus(0);
                } else {
                    onDutySettlementVo.setSettlementStatus(payOrderVo.getSettlementStatus());
                }

                String parkingSerial = payOrderVo.getParkingSerial();

                // 处理进出场信息
                handleInAndOutInfo(onDutySettlementVo, SecurityUtils.getParkId(), parkingSerial);

                onDutySettlementVoList.add(onDutySettlementVo);
            });
        }
        return onDutySettlementVoList;
    }

    private void handleInAndOutInfo(OnDutySettlementVo onDutySettlementVo, Long parkId, String parkingSerial) {
        // 查询进场信息
        List<ParkInDto> parkInDtoList = parkInService.selectParkInByParkingSerial(parkId, parkingSerial);
        if (CollectionUtils.isNotEmpty(parkInDtoList)) {
            ParkInDto parkIn = parkInDtoList.get(0);
            onDutySettlementVo.setInTime(parkIn.getInTime());
            onDutySettlementVo.setInLaneName(parkIn.getLaneName());
            onDutySettlementVo.setMngType(parkIn.getMngType());
            onDutySettlementVo.setInTye(parkIn.getInType());
            onDutySettlementVo.setInPic(StrUtil.isNotBlank(parkIn.getInPic()) ? aliossUtil.getJzyGetObjectUrl(parkIn.getInPic()).toString() : "");
        }

        // 查询出场信息
        List<ParkOutDto> parkOutDtoList = parkOutService.selectParkOutByParkingSerial(parkId, parkingSerial);
        if (CollectionUtils.isNotEmpty(parkOutDtoList)) {
            ParkOutDto parkOut = parkOutDtoList.get(0);
            onDutySettlementVo.setOutTime(parkOut.getOutTime());
            onDutySettlementVo.setOutLaneName(parkOut.getLaneName());
            onDutySettlementVo.setTrafficStatus(1);
            onDutySettlementVo.setMngType(parkOut.getMngName());
            onDutySettlementVo.setOutType(parkOut.getOutType());
            onDutySettlementVo.setOutPic(StrUtil.isNotBlank(parkOut.getOutPic()) ? aliossUtil.getJzyGetObjectUrl(parkOut.getOutPic()).toString() : "");
        } else {
            onDutySettlementVo.setTrafficStatus(0);
        }
    }

}
